<?php

App::uses('CustomDataModel', 'Base.Model');
App::uses('ConfigurationKeys', 'ConfigurationKeys.Lib');
App::uses('Basics', 'Base.Lib');
App::uses('FileOperations', 'Operations.Lib');
App::uses('SourceDocument', 'Model');

class RawFile extends CustomDataModel {

    public $displayField = 'name';
    public $belongsTo = array(
        'SourceDocument',
    );
    public $validate = array(
        'name' => array(
            'notempty' => array(
                'rule' => array('notempty'),
                'required' => true,
            ),
            'isUnique' => array(
                'rule' => array('isUnique'),
            ),
        )
    );

    protected function customData() {
        $rawFilesDirectory = ConfigurationKeys::getRequiredKeyValue('raw_files_directory');
        if (!is_readable($rawFilesDirectory) || !is_dir($rawFilesDirectory)) {
            return array();
        }
        $rawFilesDirectoryIterator = new DirectoryIterator($rawFilesDirectory);

        $data = array();

        while ($rawFilesDirectoryIterator->valid()) {
            if (!$rawFilesDirectoryIterator->isDot()) {
                $sourceDocument = $this->SourceDocument->findByName(
                        $this->SourceDocument->buildNameFromFileName(
                                $rawFilesDirectoryIterator->getFilename()
                        )
                );
                if (empty($sourceDocument)) {
                    throw new Exception("Source document not found for \"{$rawFilesDirectoryIterator->getFilename()}\"");
                }

                $data[] = array(
                    'name' => $rawFilesDirectoryIterator->getFilename(),
                    'is_writable' => $rawFilesDirectoryIterator->isWritable(),
                    'source_document_id' => $sourceDocument['SourceDocument']['id']
                );
            }
            $rawFilesDirectoryIterator->next();
        }

        return $data;
    }

    protected function customSave($oldData, $newData) {
        if (empty($oldData)) {
            $path = ConfigurationKeys::getKeyValue('raw_files_directory') . DS . $newData['name'];
            if (file_exists($path)) {
                $this->validationErrors['name'] = "File already exists: \"$path\"";
            }
            $this->executeOperation(FileOperations::touch($path));
        } else {
            if ($oldData['name'] != $newData['name']) {
                $oldRawFile = $this->findById($oldData['id']);

                $this->executeOperation(
                        FileOperations::rename(
                                $this->getAbsolutePath($oldRawFile), $this->getAbsolutePath(array($this->alias => $newData)))
                );
            }
        }

        $this->data[$this->alias]['source_document_id'] =
                $this->_fixSourceDocumentId($oldData, $newData);
    }

    public function afterSave($created) {
        parent::afterSave($created);

        $RawFileTag = ClassRegistry::init('RawFileTag');
        $rawFileTags = $RawFileTag->findAllByRawFileId($this->id);

        foreach ($rawFileTags as $rawFileTag) {
            Basics::deleteModelOrThrowException($RawFileTag, $rawFileTag);
            $rawFileTag['RawFileTag']['name'] = $this->data[$this->alias]['name'];
            $RawFileTag->create();
            Basics::saveModelOrThrowException($RawFileTag, $rawFileTag);
        }
    }

    public function _fixSourceDocumentId($oldData, $newData) {
        $SourceDocument = new SourceDocument(false, null, $this->useDbConfig);
        //Old source document
        $oldSourceDocument = $SourceDocument->findById($oldData['source_document_id']);

        //New source document
        $newSourceDocument = $SourceDocument->findByName(
                $SourceDocument->buildNameFromFileName($newData['name'])
        );

        if (empty($newSourceDocument)) {
            $SourceDocument->create();
            $SourceDocument->cacheSave(array(
                $SourceDocument->alias => array(
                    'name' => $SourceDocument->buildNameFromFileName($newData['name'])
                )
                    )
            );
            $sourceDocumentId = $SourceDocument->id;
        } else {
            $sourceDocumentId = $newSourceDocument['SourceDocument']['id'];
        }

        if (!empty($oldSourceDocument) && $oldSourceDocument['SourceDocument']['id'] != $sourceDocumentId && !empty($newData['id'])) {
            $this->_removeSourceDocumentIfNotUsed($oldSourceDocument['SourceDocument']['id'], $newData['id']);
        }

        return $sourceDocumentId;
    }

    private function _removeSourceDocumentIfNotUsed($sourceDocumentId, $excludeRawFileId) {
        $count = $this->find('count', array(
            'conditions' => array(
                'RawFile.source_document_id' => $sourceDocumentId,
                'RawFile.id <>' => $excludeRawFileId
            )
                ));
        if ($count == 0) {
            $this->SourceDocument->cacheDelete($sourceDocumentId);
        }
    }

    protected function customDelete($row) {
        $this->executeOperation(FileOperations::unlink($this->getAbsolutePath(array($this->alias => $row))));
        $this->_removeSourceDocumentIfNotUsed($row['source_document_id'], $row['id']);

    }

    public function getDirectoryPath($rawFile) {
        return ConfigurationKeys::getRequiredKeyValue('raw_files_directory');
    }

    public function getAbsolutePath($rawFile) {
        return $this->getDirectoryPath($rawFile) . DS . $rawFile[$this->alias]['name'];
    }

    public function findByAbsolutePath($absolutePath) {
        $rawFile = $this->findByName(basename($absolutePath));
        if ($this->getDirectoryPath($rawFile) == dirname($absolutePath)) {
            return $rawFile;
        } else {
            return false;
        }
    }

}